#include <iostream>
#include <string>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define MAXLINE 4096

using namespace std;

int main(int argc, char **argv)
{
    int listenfd, acceptfd;
    struct sockaddr_in servaddr;
    // 绑定端口和准备收包
    //  根据地址类型创建了一个TCP的socket，如果出错打印出错码
    //  socket参数：(协议域如ipv4，socket类型如tcp，指定协议若0时自动选择)
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        cout << "create socket error:" << strerror(errno) << "(errno:" << errno << ")" << endl;
        return -1;
    }
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    // INADDR_ANY一般指定系统中的0.0.0.0地址
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6666);
    // 将地址绑定在listenfd上
    // bind参数：(socket描述字，一个const struct sockaddr*指针指向要绑定socketfd的协议地址)
    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        cout << "bind socket error:" << strerror(errno) << "(errno:" << errno << ")" << endl;
        return -1;
    }
    // 监听这个listenfd，若客户端调用connect()发出请求，服务器端就会收到
    // listen参数：(要监听的socket描述字，相应socket可以排队的最大连接个数)
    if (listen(listenfd, 10) == -1)
    {
        cout << "listen socket error:" << strerror(errno) << "(errno:" << errno << ")" << endl;
        return -1;
    }
    cout << "======waiting for client's request======" << endl;
    // 在while循环中持续接收包，accpet和recv都在循环中，即收到包后fd关闭，下个包重新接收包
    // TCP服务器监听到请求后，调用accept()函数，连接就建立好了
    // accpet参数：(服务器socket描述字，指向struct sockaddr*的指针用于返回客户端的协议地址，协议地址长度)
    // 若accpet成功，返回值是由内核自动生成的一个全新的描述字，代表与返回客户的TCP连接
    // accpet的第一个参数是服务器的监听socket描述字，只创建一个
    // accept函数返回的是已连接的socket描述字，内核为每个由服务器进程接受的客户创建了一个已连接的socket描述字，当服务器完成服务，相应的已连接socket描述字就被关闭
    if ((acceptfd = accept(listenfd, (struct sockaddr *)NULL, NULL)) == -1)
    {
        cout << "accept socket error:" << strerror(errno) << "(errno:" << errno << ")" << endl;
    }
    else
    {
        cout << "accept succ" << endl;
    }
    int rcvbuf_len;
    socklen_t len = sizeof(rcvbuf_len);
    // 打印了接收缓冲区的大小（perror也可以打印出相应的错误日志）
    if (getsockopt(acceptfd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf_len, &len) < 0)
    {
        perror("getsocketopt: ");
    }
    cout << "the recv buf len: " << rcvbuf_len << endl;
    char recvMsg[246988] = {0};
    ssize_t totalLen = 0;
    // 服务端每收一次包后，就休眠一次，休眠完毕继续接收包，而未接收的数据存储在接收缓冲区里
    while (1)
    {
        sleep(1);
        ssize_t readLen = read(acceptfd, recvMsg, sizeof(recvMsg));
        cout << "readLen: " << readLen << endl;
        if (readLen < 0)
        {
            perror("read: ");
            return -1;
        }
        else if (readLen == 0)
        {
            cout << "read finish: len = " << totalLen << endl;
            close(acceptfd);
            return 0;
        }
        else
        {
            totalLen += readLen;
        }
    }
    close(acceptfd);
    return 0;
}
